package belf.migrate.evaluate.helper;

import belf.migrate.api.exception.CatalogException;
import belf.migrate.api.exception.ViewNotExistException;
import belf.migrate.api.job.Job;
import belf.migrate.api.model.CharacteristicInfo;
import belf.migrate.api.model.QualifiersModel;
import belf.migrate.api.table.schema.AbstractJdbcCatalog;
import belf.migrate.api.table.schema.TablePath;
import belf.migrate.api.taskconf.JobContext;
import belf.migrate.api.type.DbObjectType;
import belf.migrate.api.type.LogLevelType;
import belf.migrate.api.type.MatchingType;
import belf.migrate.api.util.DatabaseType;
import belf.migrate.api.util.PostLog;
import belf.migrate.evaluate.model.EvaluateBaseModel;
import belf.migrate.evaluate.model.EvaluateSinkResult;
import belf.migrate.evaluate.model.EvaluateViewResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static belf.migrate.api.job.JobCode.EXECUTING;


@Slf4j
public class EvaluateViewTool extends EvaluateBaseTool {

    private AbstractJdbcCatalog catalog;

    public EvaluateViewTool(JobContext jobContext, Job job) {
        super(jobContext, job);
        this.catalog = jobContext.getSourceCatalog();

    }

    @Override
    public EvaluateViewResult run() {

        String taskType = job.getTask().getTaskConf().getTaskType();
        String[] catalogs = taskType.split("-");

        DatabaseType sourceDatabaseType = DatabaseType.getDatabaseType(job.getTask().getTaskConf().getSourceConf().getCatalogName());
        if (!(sourceDatabaseType != null && sourceDatabaseType.getObjectTypes().contains(DbObjectType.VIEW))) {
            log.info("当前数据库不支持视图评估!");
            return null;
        }
        EvaluateViewResult result = new EvaluateViewResult();

        PostLog.sendLogModel(
                job.getJobId(),
                job.getTask().getTaskType().getName(),
                "开始进行视图评估!",
                LogLevelType.INFO.getType(),
                EXECUTING,
                jobContext.getProgress());
        log.info("开始进行视图评估!");

        Map<String, List<EvaluateBaseModel>> viewListMap = new HashMap<>();
        Map<String, EvaluateSinkResult> sinkResultMap = new HashMap<>();
        String databaseName = job.getTask().getTaskConf().getSourceConf().getDatabaseName();
        String schemaName = job.getTask().getTaskConf().getSourceConf().getSchemaName();
        QualifiersModel qualifiersModel = getSourceQualifiersModel();

        Map<String, Map<String, Integer>> functionRiskMap = new HashMap<>();
        try {
            List<String> viewList;
            if (CollectionUtils.isEmpty(job.getMissions())) {
                viewList = catalog.listViewNames(databaseName, schemaName);
            } else {
                viewList = job.getMissions();
            }

            result.setAllObjectSize(viewList.size());
            for (int index = 0; index < viewList.size(); index++) {

                jobContext.addProgress(DbObjectType.VIEW.getTypeName(), viewList.size());
                long startTime = System.currentTimeMillis();
                MatchingType matchingType = MatchingType.FULL_MATCH;
                TablePath tablePath = TablePath.of(databaseName, schemaName, viewList.get(index), qualifiersModel);
                String ddl = catalog.showCreateView(tablePath);
                List<CharacteristicInfo> characteristicInfo = catalog.getCharacteristicInfo(ddl);
                for (int i=0;i<job.getTask().getTaskConf().getEvaluateConf().getSinkDbs().size();i++) {
                    String sinkCatalog = job.getTask().getTaskConf().getEvaluateConf().getSinkDbs().get(i);
                    taskType = String.format("%s-%s", catalogs[0], sinkCatalog);
                    DatabaseType sinkDatabaseType = DatabaseType.getDatabaseType(sinkCatalog);
                    if (!(sinkDatabaseType != null && sinkDatabaseType.getObjectTypes().contains(DbObjectType.VIEW))) {
                        result.getNotSupportCatalogs().add(sinkCatalog);
                        continue;
                    }
                    EvaluateSinkResult sinkResult = getSinkResultList(sinkResultMap, sinkCatalog);
                    List<EvaluateBaseModel> viewModelList = getBaseModelByMap(viewListMap, sinkCatalog);
                    EvaluateBaseModel baseModel = new EvaluateBaseModel();
                    baseModel.setDatabaseName(databaseName);
                    baseModel.setSchemaName(schemaName);
                    baseModel.setName(viewList.get(index));
                    baseModel.setDdlSql(ddl);

                    if (StringUtils.isNotEmpty(ddl)) {

                        matchingType = functionDiff(ddl, catalogs, taskType, matchingType, baseModel, functionRiskMap, sinkCatalog);

                        matchingType = characteristic(baseModel, matchingType, characteristicInfo);
                    }

                    baseModel.setMatchType(matchingType.getType());

                    //计算耗时
                    long endTime = System.currentTimeMillis();
                    String timeConsuming = String.valueOf((double) (endTime - startTime) / 1000);
                    baseModel.setTimeConsuming(String.format("%s秒", timeConsuming));
                    viewModelList.add(baseModel);
                    viewListMap.put(sinkCatalog, viewModelList);
                    switch (matchingType.getId()) {
                        case 0:
                            sinkResult.addCompatibleSize(viewList.size());
                            break;
                        case 1:
                            sinkResult.addConvertSize(viewList.size());
                            break;
                        case 2:
                            sinkResult.addUnCompatibleSize(viewList.size());
                            break;
                        default:
                            sinkResult.addUnKnownSize(viewList.size());
                            break;
                    }
                    sinkResultMap.put(sinkCatalog, sinkResult);
                }

                String curLogMsg = String.format("视图 %s 评估已完成，目前进度：%s / %s.", viewList.get(index), index + 1, viewList.size());
                PostLog.sendLogModel(
                        job.getJobId(),
                        job.getTask().getTaskType().getName(),
                        curLogMsg,
                        LogLevelType.INFO.getType(),
                        EXECUTING,
                        jobContext.getProgress());
                log.info(curLogMsg);
            }
            result.setObjectList(viewListMap);
            result.setSinkStatisticsMap(sinkResultMap);

            result.setFunctionRisk(functionRiskMap);
        } catch (CatalogException | ViewNotExistException e) {
            log.error("视图评估失败！", e);
            PostLog.sendLogModel(
                    job.getJobId(),
                    job.getTask().getTaskType().getName(),
                    String.format("视图评估失败: %s", e.getMessage()),
                    LogLevelType.ERROR.getType(),
                    EXECUTING,
                    jobContext.getProgress());
        }
        log.info("视图评估成功完成!");
        PostLog.sendLogModel(
                job.getJobId(),
                job.getTask().getTaskType().getName(),
                "视图评估成功完成!",
                LogLevelType.INFO.getType(),
                EXECUTING,
                jobContext.getProgress());
        return result;
    }


}
